"""SQL文件工具类"""

from typing import Optional, List, Callable, Dict, Any, Tuple
from pathlib import Path
import argparse
import json
import shutil
from src.base.registry import bera

from .sql_utils.sql_args_utils import SQLArgsUtils
from .sql_utils.sql_path_utils import SQLPathUtils
from .sql_utils.sql_file_ops import SQLFileOps
from .sql_utils.sql_search_utils import SQLSearchUtils
from .sql_utils.sql_config_validator import SQLConfigValidator

class SQLFileUtils(SQLArgsUtils, SQLPathUtils, SQLFileOps, SQLSearchUtils, SQLConfigValidator):
    """SQL文件工具类

    处理SQL文件的搜索、读取等操作。

    主要功能:
    1. SQL文件搜索和读取
    2. 搜索路径管理
    3. 命令行参数处理
    4. 路径处理
    5. 目录操作
    6. 文件操作

    支持三种模式：
    1. 目录模式：处理目录下的所有文件
    2. 文件路径模式：处理单个完整路径的文件
    3. 文件名模式：使用不带后缀的文件名，系统自动查找对应文件
    """

    @classmethod
    def execute_file_processing(cls, args: argparse.Namespace, process_func: Callable[[str, argparse.Namespace], None]) -> None:
        """处理输入模式并执行相应的处理函数

        Args:
            args: 命令行参数，必须包含以下字段之一：
                 - filename: 不带后缀的文件名
                 - filepath: 文件的完整路径
                 - directory: 文件所在目录
            process_func: 处理单个文件的函数，接收两个参数：
                        - filepath: str 文件路径
                        - args: argparse.Namespace 命令行参数

        Raises:
            ValueError: 当输入模式参数无效或冲突时
            FileNotFoundError: 当文件或目录不存在时
        """
        try:
            # 获取输入模式
            input_mode = cls.get_input_mode(args)

            # 验证输入模式
            if input_mode == 'filename':
                # 查找SQL文件
                sql_file = cls.find_sql_file(args.filename)
                if not sql_file:
                    raise FileNotFoundError(f"找不到SQL文件: {args.filename}")
                process_func(sql_file, args)
            elif input_mode == 'filepath':
                # 检查文件是否存在
                if not Path(args.filepath).exists():
                    raise FileNotFoundError(f"文件不存在: {args.filepath}")
                process_func(args.filepath, args)
            else:  # directory mode
                # 检查目录是否存在
                if not Path(args.directory).exists():
                    raise FileNotFoundError(f"目录不存在: {args.directory}")
                cls.process_directory(args.directory, process_func, args)

        except Exception as e:
            if args.verbose:
                import traceback
                traceback.print_exc()
            if hasattr(args, 'filepath') and args.filepath:
                cls.handle_file_error(e, str(args.filepath))
            else:
                raise

    @classmethod
    def process_directory(cls, directory: str, process_func: Callable[[str, argparse.Namespace], None], args: argparse.Namespace) -> None:
        """处理目录中的所有SQL文件

        Args:
            directory: 目录路径
            process_func: 处理单个文件的函数
            args: 命令行参数

        Raises:
            FileNotFoundError: 目录不存在
            Exception: 处理失败时抛出,包含失败的表数量和名称
        """
        dir_path = Path(directory)
        if not dir_path.exists():
            raise FileNotFoundError(f"目录不存在: {directory}")

        # 列出目录中的所有SQL文件
        sql_files = [f for f in dir_path.glob("*.sql")]
        if not sql_files:
            bera.logger.warning(f"目录中没有SQL文件: {directory}")
            return

        # 对SQL文件进行排序，确保处理顺序固定
        sql_files.sort(key=lambda x: x.name)
        bera.logger.info(f"发现SQL文件 ({len(sql_files)} 个): {[f.name for f in sql_files]}")

        # 处理每个SQL文件
        success_count = 0
        fail_count = 0
        failed_tables = []

        for sql_file in sql_files:
            try:
                # 创建新的参数对象，避免修改原始参数
                file_args = argparse.Namespace(**vars(args))
                file_args.filepath = str(sql_file)
                file_args.filename = None
                file_args.directory = None
                # 确保必要的参数存在
                file_args.verbose = getattr(args, 'verbose', False)
                file_args.format_create = getattr(args, 'format_create', False)
                file_args.format_insert = getattr(args, 'format_insert', False)
                file_args.force = getattr(args, 'force', False)
                file_args.output = getattr(args, 'output', 'artifacts/miaoma')

                bera.logger.info(f"🔄 开始处理文件: {sql_file.name}")
                process_func(str(sql_file), file_args)
                bera.logger.info(f"✅ 文件处理成功: {sql_file.name}")
                success_count += 1
            except Exception as e:
                fail_count += 1
                failed_tables.append(sql_file.stem)
                bera.logger.error(f"❌ 处理文件失败: {sql_file.name} - {str(e)}")
                if args.verbose:
                    import traceback
                    traceback.print_exc()

        # 输出处理结果统计
        bera.logger.info(f"目录处理完成:")
        bera.logger.info(f"- 成功: {success_count}")
        bera.logger.info(f"- 失败: {fail_count}")
        if failed_tables:
            bera.logger.info(f"- 失败的表: {', '.join(failed_tables)}")

        # 如果有失败的表，抛出异常
        if fail_count > 0:
            raise Exception(f"目录处理完成，但有 {fail_count} 个表处理失败")

    @classmethod
    def process_config_file(cls, artifacts_file: Path, assets_file: Path, generate_func: Callable, force: bool = False, verbose: bool = False) -> None:
        """处理配置文件

        Args:
            artifacts_file: 生成的配置文件路径
            assets_file: 资产目录中的配置文件路径
            generate_func: 生成配置文件的函数
            force: 是否强制重新生成
            verbose: 是否显示详细日志
        """
        # 确保目录存在
        artifacts_file.parent.mkdir(parents=True, exist_ok=True)

        # 如果不是强制模式，检查是否可以复用已有配置
        if not force:
            # 检查 assets_config_dir 中是否存在对应配置
            if assets_file.exists():
                if verbose:
                    bera.logger.debug(f"复制已有配置文件: {assets_file} -> {artifacts_file}")
                shutil.copy2(assets_file, artifacts_file)
                return
            elif artifacts_file.exists():
                if verbose:
                    bera.logger.debug(f"配置文件已存在且未指定force,保留原有内容: {artifacts_file}")
                return

        # 生成配置文件
        if verbose:
            bera.logger.debug(f"生成配置文件: {artifacts_file}")

        # 生成配置内容
        try:
            config_data = generate_func(artifacts_file)
        except TypeError:
            # 如果 generate_func 不接受参数，则不传参调用
            config_data = generate_func()

        # 写入配置文件
        cls.write_json_file(artifacts_file, config_data, verbose)

        # 保存到 assets 目录
        assets_file.parent.mkdir(parents=True, exist_ok=True)
        if verbose:
            bera.logger.debug(f"复制配置文件到资产目录: {assets_file}")
        shutil.copy2(artifacts_file, assets_file)